package com.zrx.govern.component.easyexcel.starter.listener;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.IterUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zrx.govern.component.easyexcel.starter.constants.ExcelCheckConstants;
import com.zrx.govern.component.easyexcel.starter.constants.RedisConstants;
import com.zrx.govern.component.easyexcel.starter.entity.*;
import com.zrx.govern.component.easyexcel.starter.enums.BusinessRuleEnum;
import com.zrx.govern.component.easyexcel.starter.enums.ImportType;
import com.zrx.govern.component.easyexcel.starter.enums.ValidEnum;
import com.zrx.govern.component.easyexcel.starter.service.EasyExcelService;
import com.zrx.govern.component.easyexcel.starter.utils.ExcelBeanUtil;
import com.zrx.govern.component.easyexcel.starter.utils.JsonParseUtil;
import com.zrx.govern.component.easyexcel.starter.validate.ExcelValidator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.zrx.govern.component.easyexcel.starter.constants.ExcelCheckConstants.UNION_DELIMITER;
import static com.zrx.govern.component.easyexcel.starter.enums.BusinessRuleEnum.UNIQUE;
import static com.zrx.govern.component.easyexcel.starter.enums.ImportType.BUSINESS_IMPORT;
import static com.zrx.govern.component.easyexcel.starter.enums.ImportType.NORMAL_IMPORT;

/**
 * @author zhangxiaowei
 * @desc excel通用解析器
 */
@Slf4j
public class ExcelAnalysisListener extends AnalysisEventListener<Map<Integer, Object>> {

    /**
     * 缓存所有解析的数据（带错误信息）
     * key-value格式：key为字段的enName
     */
    private List<JSONObject> dataList = new ArrayList<>(8);
    /**
     * 字段约束
     */
    private Map<Integer, List<FieldRule>> rules;

    /**
     * 通用校验
     */

    private ExcelValidator excelValidator;

    /**
     * 导入类型
     */
    private List<ImportType> importType;

    /**
     * 业务类型
     */
    private String model;

    /**
     * 缓存校验通过的数据
     */
    private List<JSONObject> checkPassList = new ArrayList<>(8);

    /**
     * 唯一性校验有错误的集合
     */
    Map<String, List<Object>> uniqueErrorMap = new HashMap<>(8);
    /**
     * 数字列索引和字段key(enName)名称映射
     */
    private Map<Integer, String> indexEnNameMap = new HashMap<>(6);

    /**
     * 计算校验进度的对象
     */
    private ExcelCheckImportProcess excelCheckImportProcess;

    private RedisTemplate redisTemplate;

    private BigDecimal total;

    private BigDecimal hundredBigDecimal;

    /**
     * 是否进行业务校验
     */
    private boolean isCheckBusiness = false;
    /**
     * 取消导入的key
     */
    private String uploadCancelKey;

    /**
     * 当前导入的文件个数,控制doAfterAllAnalysed的执行，当fileNumber=1时执行doAfterAllAnalysed
     */
    private int fileNumber;

    /**
     * 控制计算进度的速率(每20条计算一次进度)
     */
    private static final Integer CACHE_COUNT = 20;

    public ExcelAnalysisListener(Map<Integer, List<FieldRule>> rules, List<ImportType> importType,
                                 ExcelValidator excelValidator, String model, ExcelCheckImportProcess excelCheckImportProcess, RedisTemplate redisTemplate,
                                 int fileNumber) {
        this.rules = rules;
        this.importType = importType;
        this.excelValidator = excelValidator;
        this.model = model;
        this.excelCheckImportProcess = excelCheckImportProcess;
        this.redisTemplate = redisTemplate;
        this.fileNumber = fileNumber;
        hundredBigDecimal = new BigDecimal(100);
        /*excelCheckImportProcess不为空,说明开启了进度开关*/
        if (Objects.nonNull(excelCheckImportProcess) && importType.contains(BUSINESS_IMPORT)) {
            isCheckBusiness = true;
        }
        /*设置取消导入key,初始化设置为false(不取消)*/
        this.uploadCancelKey = RedisConstants.EXCEL_UPLOAD_CANCEL + model;
        redisTemplate.boundValueOps(uploadCancelKey).set(false);
        /*如果包含业务校验，将excel总行数新增n倍(业务逻辑校验字段个数)，控制常规校验完进度的百分比*/
        /*eg: 假如excel有1000行数据，有三个字段进行业务校验,则常规校验完进度为25%*/
        if (Objects.nonNull(excelCheckImportProcess) && (importType.contains(BUSINESS_IMPORT) || importType.contains(BUSINESS_IMPORT))) {
            int cnt = getBusinessFieldCount() + 1;
            total = new BigDecimal(excelCheckImportProcess.getTotal() * cnt);
        }
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(Map<Integer, Object> data, AnalysisContext context) {
        /*常规字段校验*/
        if (importType.contains(NORMAL_IMPORT)) {
            String msg = this.excelValidator.validate(rules, data, model);
            if (msg.length() > 0) {
                /*添加至data最后一列-错误信息列*/
                data.put(rules.size(), msg);
            }
        }
        /*和indexEnNameMap和index做映射,生成json数据(key为filedEnName)*/
        JSONObject json = new JSONObject(data.size());
        data.keySet().forEach(index -> json.put(indexEnNameMap.get(index), data.get(index)));
        dataList.add(json);
        /*进行校验进度计算*/
        if (Objects.nonNull(excelCheckImportProcess)) {
            int curr = excelCheckImportProcess.increment();
            calRadio(curr);
        }
    }

    /**
     * 计算校验占比
     *
     * @param curr 分子
     * @return 百分比
     */
    private void calRadio(int curr) {
        if (curr % CACHE_COUNT == 0 || curr == excelCheckImportProcess.getTotal()) {
            /*判断是否取消导入*/
            Boolean isCancel = (Boolean) redisTemplate.boundValueOps(uploadCancelKey).get();
            if (isCancel) {
                log.info("导入终止...");
                throw new RuntimeException("导入终止...");
            }
            //计算插入的数据和总数据的占比
            String progress = new BigDecimal(curr).divide(total, 2, BigDecimal.ROUND_HALF_UP).multiply(hundredBigDecimal).toString();
            redisTemplate.opsForValue().set(excelCheckImportProcess.getCheckRedisKey(), progress, 5, TimeUnit.SECONDS);
        }
    }

    /**
     * 计算校验占比
     *
     * @param curr     分子
     * @param newTotal 总数
     * @return 百分比
     */
    private void calRadio(int curr, BigDecimal newTotal) {
        //计算插入的数据和总数据的占比
        String progress = new BigDecimal(curr).divide(newTotal, 2, BigDecimal.ROUND_HALF_UP).multiply(hundredBigDecimal).toString();
        redisTemplate.opsForValue().set(excelCheckImportProcess.getCheckRedisKey(), progress, 5, TimeUnit.SECONDS);
    }

    /**
     * 获取业务逻辑要校验的字段个数
     *
     * @return
     */
    private int getBusinessFieldCount() {
        AtomicInteger count = new AtomicInteger();
        rules.keySet().forEach(index -> {
            List<FieldRule> fieldRules = rules.get(index);
            fieldRules.forEach(fieldRule -> {
                if (ValidEnum.BUSINESS_CHECK.equals(fieldRule.getType())) {
                    count.getAndIncrement();
                }
            });
        });
        return count.get();
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        if (fileNumber == 1) {
            try {
                /*判断是否取消导入*/
                Boolean isCancel = (Boolean) redisTemplate.boundValueOps(uploadCancelKey).get();
                if (isCancel) {
                    log.info("导入终止...");
                    throw new RuntimeException("导入终止...");
                }
                /*无业务校验*/
                if (!isCheckBusiness) {
                    /*常规校验*/
                    if (importType.contains(NORMAL_IMPORT)) {
                        /*遍历获取通过校验的数据*/
                        checkPassList = dataList.stream().filter(jsonObject ->
                                Objects.isNull(jsonObject.get(ExcelCheckConstants.ERROR_MSG))).collect(Collectors.toList());
                    }
                    return;
                }
                log.info("开始业务校验。。。。。。。。。。。。。");
                /*获取业务校验相关信息，组装成BusinessCondition对象*/
                List<BusinessCondition> businessConditions = getBusinessCondition();
                /**
                 * 获取非唯一性校验和通过唯一性校验的List<JSONObject>集合
                 * 其内JSONObject格式：key为业务校验字段key，value为key对应的值
                 */
                List<JSONObject> jsonObjects = getJsonObjects(businessConditions);
                /*调第三方业务校验接口*/
                Map<String, List<Object>> validateResult = checkJsonObjects(businessConditions, jsonObjects);
                /*将校验后的错误信息添加至dataList*/
                addErrorMsg2JsonObject(validateResult, businessConditions);
                /*遍历获取通过校验的数据*/
                checkPassList =
                        dataList.stream().filter(jsonObject -> Objects.isNull(jsonObject.get(ExcelCheckConstants.ERROR_MSG))).collect(Collectors.toList());
            } finally {
                /*确保最后删除uploadCancelKey*/
                if (redisTemplate.hasKey(uploadCancelKey)) {
                    redisTemplate.delete(uploadCancelKey);
                }
            }
        } else {
            fileNumber--;
        }
    }

    /**
     * 添加错误信息至dataList内的jsonObject的ExcelCheckConstants.ERROR_MSG列
     *
     * @param validateResult
     * @param businessConditions
     */
    private void addErrorMsg2JsonObject(Map<String, List<Object>> validateResult, List<BusinessCondition> businessConditions) {
        /*将excel内数据校验错误信息和第三方返回的错误信息进行拼接*/
        for (String key : validateResult.keySet()) {
            List<Object> objects = validateResult.get(key);
            if (!Objects.isNull(uniqueErrorMap.get(key))) {
                objects.addAll(uniqueErrorMap.get(key));
                validateResult.put(key, objects);
            }
        }
        /*遍历数据dataList和校验异常有误的数据validateResult集合，匹配出校验异常的数据*/
        StringBuilder stringBuilder = new StringBuilder();
        for (JSONObject jsonObject : dataList) {
            for (String key : validateResult.keySet()) {
                List<Object> errorValList = validateResult.get(key);
                /*获取key设置的errorMsg*/
                String businessMsg = getBusinessMsg(businessConditions, key);
                boolean flag = key.contains(UNION_DELIMITER);
                String[] arr = key.split(UNION_DELIMITER);
                errorValList.forEach(o -> {
                    if (flag) {
                        for (String val : arr) {
                            stringBuilder.append(jsonObject.getString(val)).append(UNION_DELIMITER);
                        }
                        // 判断数据库里面的数据和excel中的数据哪条记录重复了
                        if (o.equals(stringBuilder.deleteCharAt(stringBuilder.length() - 1).toString())) {
                            jsonObject.put(ExcelCheckConstants.ERROR_MSG, getMsg(businessMsg, jsonObject));
                        }
                        stringBuilder.setLength(0);
                    } else {
                        if (o.equals(jsonObject.get(key))) {
                            jsonObject.put(ExcelCheckConstants.ERROR_MSG, getMsg(businessMsg, jsonObject));
                        }
                    }
                });

            }
        }
        //去除重复的提示信息
        for (JSONObject jsonObject : dataList) {
            String value = jsonObject.getString(ExcelCheckConstants.ERROR_MSG);
            if (StringUtils.isNotBlank(value)) {
                String collect = Arrays.stream(value.split(";")).distinct().collect(Collectors.joining(";"));
                jsonObject.put(ExcelCheckConstants.ERROR_MSG, collect);
            }
        }
    }

    /**
     * 遍历当前model的所有字段的FieldRules,获取业务校验BusinessCondition集合
     */
    private List<BusinessCondition> getBusinessCondition() {
        List<BusinessCondition> businessConditions = new ArrayList<>(rules.size());
        /*单字段*/
        rules.keySet().forEach(index -> {
            List<FieldRule> fieldRules = rules.get(index);
            fieldRules.forEach(fieldRule -> {
                if (ValidEnum.BUSINESS_CHECK.equals(fieldRule.getType())) {
                    if (StringUtils.isBlank(fieldRule.getBusinessRule())) {
                        throw new RuntimeException(String.format("json文件model为%s的字段businessRule不允许为空", model));
                    }
                    if (Objects.isNull(fieldRule.getCheckBean()) || StringUtils.isBlank(fieldRule.getCheckBean().getCheckMethod())) {
                        throw new RuntimeException(String.format("json文件model为%s的字段checkMethod在业务类型为6时不允许为空", model));
                    }
                    String enName = indexEnNameMap.get(index);
                    businessConditions.add(new BusinessCondition().setIndex(index).setFieldEnName(enName).setBusinessMsg(fieldRule.getMsg())
                            .setCheckMethod(fieldRule.getCheckBean().getCheckMethod()).setBeanName(fieldRule.getCheckBean().getBeanName())
                            .setBusinessRule(BusinessRuleEnum.getEnumFromString(BusinessRuleEnum.class,
                                    fieldRule.getBusinessRule())));
                }
            });
        });
        /*组合字段唯一性校验处理*/
        JsonParseUtil.getUnionUniqueFields(model).forEach(unionCheckField -> {
            businessConditions.add(new BusinessCondition().setFieldEnName(unionCheckField.getFields()).setBusinessMsg(unionCheckField.getMsg())
                    .setCheckMethod(unionCheckField.getCheckMethod()).setBeanName(unionCheckField.getCheckBean())
                    .setBusinessRule(BusinessRuleEnum.getEnumFromString(BusinessRuleEnum.class,
                            unionCheckField.getBusinessRule())));
        });
        return businessConditions;
    }

    /**
     * 获取key设置的errorMsg
     *
     * @param businessConditions
     * @param enName
     * @return
     */
    public String getBusinessMsg(List<BusinessCondition> businessConditions, String enName) {
        Optional<BusinessCondition> first =
                businessConditions.stream().filter(businessMsg -> businessMsg.getFieldEnName().equals(enName)).findFirst();
        return first.map(BusinessCondition::getBusinessMsg).orElse(null);
    }

    /**
     * 获取后续调用第三方进行业务校验数据的List<JSONObject>,此集合为已校验通过的满足唯一性、非唯一性业务校验的dataList的子集合(没有直接按照字段隔开)
     * 其内JSONObject格式：key为业务校验字段key，value为key对应的值
     * todo:其实更好的数据结构为Map<String,List<Object>格式，在checkJsonObjects和调用第三方时少了几层stream映射key获取数据的转换
     *
     * @param conditions
     * @return list
     */
    private List<JSONObject> getJsonObjects(List<BusinessCondition> conditions) {
        /*获取业务校验的所有字段key集合*/
        List<String> businessFields = conditions.stream()
                .map(BusinessCondition::getFieldEnName).collect(Collectors.toList());
        /*获取唯一性校验字段key集合*/
        List<String> uniqueBusinessFields = conditions.stream().filter(businessCondition -> UNIQUE.equals(businessCondition.getBusinessRule()))
                .map(businessCondition -> businessCondition.getFieldEnName()).collect(Collectors.toList());
        List<JSONObject> jsonObjectList = new ArrayList<>();
        List<JSONObject> uniqueJsonObjectList = new ArrayList<>();
        for (JSONObject data : dataList) {
            businessFields.forEach(key -> {
                /*判断是否为联合校验字段a_b_c*/
                if (Objects.nonNull(data.get(key)) || key.contains(UNION_DELIMITER)) {
                    JSONObject jsonObject = new JSONObject();
                    /*联合字段处理*/
                    if (key.contains(UNION_DELIMITER)) {
                        for (String val : key.split(UNION_DELIMITER)) {
                            if (Objects.nonNull(data.get(val))) {
                                jsonObject.put(val, data.get(val));
                                jsonObject.put("businessField", key);
                            }
                        }
                    } else {
                        jsonObject.put(key, data.get(key));
                        jsonObject.put("businessField", key);
                    }
                    if (uniqueBusinessFields.contains(key)) {
                        uniqueJsonObjectList.add(jsonObject);
                    } else {
                        /*非唯一性业务校验的json对象*/
                        jsonObjectList.add(jsonObject);
                    }
                }
            });
        }
        /*获取不满足唯一性校验的对象*/
        uniqueErrorMap = getUniqueErrorMap(uniqueJsonObjectList, uniqueBusinessFields);
        /*获取uniqueJsonObjectList内满足唯一性校验的子集合，并将其添加至jsonObjectList*/
        addVerifyUniquePass2List(jsonObjectList, uniqueJsonObjectList);
        return jsonObjectList;
    }

    /**
     * 校验当前Excel数据字段的唯一性，获取不满足唯一性校验的对象
     * 只有唯一性校验才需要当前excel内进行校验，存在性需调用第三方进行校验
     *
     * @param uniqueJsonObjectList
     * @param uniqueBusinessFields
     * @return
     */
    private Map<String, List<Object>> getUniqueErrorMap(List<JSONObject> uniqueJsonObjectList, List<String> uniqueBusinessFields) {
        Map<String, List<Object>> map = new HashMap<>(uniqueBusinessFields.size());
        StringBuilder stringBuilder = new StringBuilder();
        List<String> list = null;
        for (String key : uniqueBusinessFields) {
            if (key.contains(UNION_DELIMITER)) {
                list = new ArrayList<>(uniqueJsonObjectList.size());
                String[] arr = key.split(UNION_DELIMITER);
                for (JSONObject jsonObject : uniqueJsonObjectList) {
                    for (String val : arr) {
                        stringBuilder.append(jsonObject.getString(val)).append(UNION_DELIMITER);
                    }
                    list.add(stringBuilder.deleteCharAt(stringBuilder.length() - 1).toString());
                    /*清空stringBuilder*/
                    stringBuilder.setLength(0);
                }
            } else {
                list = uniqueJsonObjectList.stream().map(jsonObject -> (String) jsonObject.get(key)).collect(Collectors.toList());
            }
            /*计算当前集合内各个元素的个数*/
            Map<String, Long> countMap = list.stream().collect(Collectors.groupingBy(e -> e, Collectors.counting()));
            List<Object> result = countMap.entrySet().stream().filter(r -> r.getValue() > 1).map(Map.Entry::getKey).collect(Collectors.toList());
            map.put(key, result);
        }
        return map;
    }

    /**
     * 获取唯一性校验uniqueJsonObjectList集合内满足唯一性校验的子集合，并将其添加至jsonObjectList
     * 因为当前excel满足唯一性校验，不一定在数据库内满足，所以将其加入jsonObjectList，后续传入第三方校验的checkMethod进行校验
     *
     * @param jsonObjectList
     * @param uniqueJsonObjectList
     */
    private void addVerifyUniquePass2List(List<JSONObject> jsonObjectList, List<JSONObject> uniqueJsonObjectList) {
        StringBuilder stringBuilder = new StringBuilder();
        for (String key : uniqueErrorMap.keySet()) {
            List<Object> result = uniqueErrorMap.get(key);
            List<JSONObject> collect = new ArrayList<>();
            if (key.contains(UNION_DELIMITER)) {
                String[] arr = key.split(UNION_DELIMITER);
                for (JSONObject jsonObject : uniqueJsonObjectList) {
                    for (String val : arr) {
                        stringBuilder.append(jsonObject.getString(val)).append(UNION_DELIMITER);
                    }
                    if (!result.contains(stringBuilder.deleteCharAt(stringBuilder.length() - 1).toString())) {
                        collect.add(jsonObject);
                    }
                    /*清空stringBuilder*/
                    stringBuilder.setLength(0);
                }
            } else {
                collect =
                        uniqueJsonObjectList.stream().filter(jsonObject -> !result.contains((String) jsonObject.get(key))).collect(Collectors.toList());
            }
            jsonObjectList.addAll(collect);
        }
    }

    /**
     * 对业务校验字段进行反射调用，进行校验
     * 取消导入就像传入一个信号量或者一个楔子到代码逻辑运行用时占比较高的区域，去判断信号是否发生变化，以达到取消的效果
     *
     * @param businessConditions
     * @param jsonObjects
     * @return
     */
    private Map<String, List<Object>> checkJsonObjects(List<BusinessCondition> businessConditions, List<JSONObject> jsonObjects) {
        Map<String, List<Object>> map = new HashMap<>(4);
        /*获取业务bean*/
        EasyExcelService easyExcelService = ExcelBeanUtil.getEasyExcelServiceBean(model);
        /*计算进度的总数*/
        BigDecimal newTotal = new BigDecimal(excelCheckImportProcess.getTotal() + jsonObjects.size());
        AtomicInteger start = new AtomicInteger(excelCheckImportProcess.getTotal());
        /*对业务字段进行遍历，发起调用分别进行校验*/
        businessConditions.forEach(condition -> {
            /*判断是否取消导入*/
            Boolean isCancel = (Boolean) redisTemplate.boundValueOps(uploadCancelKey).get();
            if (isCancel) {
                log.info("导入终止...");
                throw new RuntimeException("导入终止...");
            }
            List<JSONObject> data = null;
            /*判断是否为联合校验字段*/
            if (condition.getFieldEnName().contains(UNION_DELIMITER)) {
                String[] arr = condition.getFieldEnName().split(UNION_DELIMITER);
                boolean flag = false;
                data = new ArrayList<>();
                /*判断当前遍历的jsonObject是否包含所有联合校验的字段*/
                for (JSONObject jsonObject : jsonObjects) {
                    data.add(jsonObject);
                }
            } else {
                data = jsonObjects.stream().filter(jsonObject -> jsonObject.containsKey(condition.getFieldEnName())).collect(Collectors.toList());
            }

            Object bean;
            /*如果定义rule的checkBean的beanName为空,beanName默认为model的beanName*/
            if (StringUtils.isNotBlank(condition.getBeanName())) {
                bean = ExcelBeanUtil.getExecuteBean(condition.getBeanName());
            } else {
                bean = easyExcelService;
            }
            map.put(condition.getFieldEnName(), checkBusinessField(bean, condition.getCheckMethod(), data,
                    condition.getFieldEnName()));
            /*计算业务校验进度*/
            start.addAndGet(data.size());
            calRadio(start.get(), newTotal);
        });
        return map;
    }

    /**
     * 反射调用bean的业务逻辑校验
     * key为联合字段时，格式为a,b,c,checkMethod希望第三方返回的数据也是val1,val2,val3
     *
     * @param bean
     * @param method
     * @param jsonObjects
     * @param key
     * @return
     */
    private List<Object> checkBusinessField(Object bean, String method,
                                            List<JSONObject> jsonObjects, String key) {
        List<Object> list = new ArrayList<>();
        try {
            Class clazz = bean.getClass();
            Method checkMethod = clazz.getDeclaredMethod(method, List.class, String.class);
            checkMethod.setAccessible(true);
            List<List<JSONObject>> partitionList = ListUtils.partition(jsonObjects, 1000);
            for (List<JSONObject> jsonObjectList : partitionList) {
                list.addAll((List<Object>) checkMethod.invoke(bean, jsonObjectList, key));
            }
        } catch (InvocationTargetException e) {
            throw new RuntimeException(String.format("反射调用%s的方法%s进行业务逻辑校验异常", bean.getClass().getName(), method), e);
        } catch (Exception e) {
            throw new RuntimeException("业务逻辑校验异常", e);
        }
        return list;
    }

    /**
     * 拼接多个业务校验字段的错误信息
     *
     * @param msg 错误信息
     * @param obj excel单行数据
     * @return
     */
    private String getMsg(String msg, JSONObject obj) {
        if (Objects.isNull(obj.get(ExcelCheckConstants.ERROR_MSG))) {
            return msg;
        } else {
            return msg + ";" + obj.get(ExcelCheckConstants.ERROR_MSG);
        }
    }

    /**
     * 抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行
     *
     * @param exception
     * @param context
     * @throws Exception
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        dataList.clear();
        /*删除取消导入key*/
        if (redisTemplate.hasKey(uploadCancelKey)) {
            redisTemplate.delete(uploadCancelKey);
        }
        throw exception;
    }

    /**
     * 校验表头是否符合模板，并初始化indexEnNameMap
     *
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        List<ExcelField> fields = JsonParseUtil.getAllFields(model);
        List<String> excelHead = fields.stream().map(ExcelField::getFieldName).collect(Collectors.toList());
        IntStream.range(0, excelHead.size()).filter(i -> !excelHead.get(i).equals(headMap.get(i))).forEach(i -> {
            throw new ExcelAnalysisException("表头与模板内容不符合:" + excelHead.get(i));
        });
        /*初始化indexEnNameMap*/
        indexEnNameMap = fields.stream().collect(Collectors.toMap(ExcelField::getIndex,
                ExcelField::getFieldEnName));
        indexEnNameMap.put(fields.size(), ExcelCheckConstants.ERROR_MSG);
    }

    public List<JSONObject> getDataList() {
        return dataList;
    }

    public List<JSONObject> getCheckPassList() {
        return checkPassList;
    }
}
